import requests
import json
import pandas as pd
from datetime import datetime, timedelta
from config import get_default_headers, print_config_info, switch_token

# 首先，我们需要从api_client.py、extract_id_frames.py和api_request_detail.py中导入相应的函数功能
# 但为了避免循环导入，我们将直接在这个文件中实现必要的函数
def get_item_abandon_list(task_id, node_id, package_ids, page_num=1, page_size=50, headers=None):
    """
    调用get-item-abandon-list接口获取废弃项目列表并返回特定字段
    
    Args:
        task_id (str): 任务ID
        node_id (str): 节点ID
        package_ids (str or list): 批次ID，可以是单个ID或ID列表
        page_num (int): 页码，默认为1
        page_size (int): 每页数量，默认为50
        headers (dict, optional): 自定义请求头，如果为None则使用默认请求头
    
    Returns:
        dict: 包含状态信息和数据的字典
    """
    # 构建请求URL
    url = "https://app.molardata.com/api/v2/item/get-item-abandon-list"
    
    # 确保package_ids是列表格式
    if isinstance(package_ids, str):
        package_ids = [package_ids]
    
    # 如果未提供自定义请求头，使用默认请求头
    if headers is None:
        referer_batch_id = package_ids[0] if package_ids else "68d28091dd785cd49b388c61"
        headers = get_default_headers(task_id=task_id, batch_id=referer_batch_id)
    
    data = {
        "taskId": task_id,
        "pageNum": page_num,
        "pageSize": page_size,
        "search": {
            "type": "AND",
            "units": []
        },
        "packageIds": package_ids,
        "nodeId": node_id
    }
    
    try:
        print("\n正在获取废弃项目列表...")
        # 打印请求参数（隐藏敏感信息）
        masked_headers = headers.copy()
        if 'access-token' in masked_headers:
            token = masked_headers['access-token']
            masked_headers['access-token'] = f"{token[:10]}****{token[-4:]}"
        print(f"请求URL: {url}")
        print(f"请求参数: taskId={task_id}, nodeId={node_id}, packageIds={package_ids}")
        print(f"请求头(部分): {dict(list(masked_headers.items())[:3])}")
        
        response = requests.post(url, headers=headers, json=data, timeout=60)
        status_code = response.status_code
        print(f"请求状态码: {status_code}")
        
        # 无论状态码如何，都尝试解析响应内容
        try:
            response_data = response.json()
            print(f"响应内容(部分): {json.dumps(response_data)[:200]}...")
        except json.JSONDecodeError:
            response_data = None
            print(f"响应内容(非JSON): {response.text[:200]}...")
        
        # 如果返回401错误，尝试切换token并重新请求
        if status_code == 401:
            print("\n[错误] 认证失败 (401 Unauthorized)")
            print("尝试切换到备用token...")
            switch_token("alternative_token")
            # 使用新token重新构建请求头
            headers = get_default_headers(task_id=task_id, batch_id=referer_batch_id)
            print("使用新token重新请求...")
            response = requests.post(url, headers=headers, json=data, timeout=60)
            status_code = response.status_code
            print(f"新请求状态码: {status_code}")
            try:
                response_data = response.json()
                print(f"新响应内容(部分): {json.dumps(response_data)[:200]}...")
            except json.JSONDecodeError:
                response_data = None
                print(f"新响应内容(非JSON): {response.text[:200]}...")
        
        result = {
            "success": False,
            "message": "",
            "total": 0,
            "data": [],
            "status_code": status_code
        }
        
        if response_data and 'data' in response_data and isinstance(response_data['data'], dict):
            total = response_data['data'].get('total', 0)
            result["total"] = total
            
            if 'data' in response_data['data'] and isinstance(response_data['data']['data'], list):
                items = response_data['data']['data']
                extracted_items = []
                
                for item in items:
                    # 提取processStatus和checkRound来判断标注状态
                    process_status = item.get('processStatus', None)
                    if process_status is not None and isinstance(process_status, dict):
                        # 结合checkRound和label字段来判断标注状态
                        has_check_round = 'checkRound' in process_status
                        label_value = process_status.get('label', '')
                        
                        # 如果label字段为LABELED且有checkRound，则为已标注
                        # 否则为标注中
                        if label_value == 'LABELED' and has_check_round:
                            annotation_status = '已标注'
                        else:
                            annotation_status = '标注中'
                    else:
                        # 如果没有processStatus对象，默认为标注中
                        annotation_status = '标注中'
                    
                    # 获取operateTime或createdAt，只保留日期部分
                    time_value = item.get('operateTime', item.get('createdAt', 'N/A'))
                    # 如果时间值不为N/A，尝试提取日期部分
                    if time_value != 'N/A':
                        # 确保时间值是字符串
                        time_str = str(time_value)
                        # 处理不同格式的时间字符串
                        if ' ' in time_str:  # 处理包含空格的格式，如"2023-10-15 12:34:56"
                            formatted_date = time_str.split(' ')[0]
                        elif 'T' in time_str:  # 处理ISO格式，如"2023-10-15T12:34:56Z"
                            formatted_date = time_str.split('T')[0]
                        elif len(time_str) >= 10:  # 处理其他可能的格式，只取前10个字符
                            formatted_date = time_str[:10]
                        else:
                            formatted_date = time_str
                    else:
                        formatted_date = 'N/A'
                    
                    extracted_items.append({
                        "_id": item.get('_id', 'N/A'),
                        "domainId": item.get('domainId', 'N/A'),
                        "operateTime": formatted_date,  # 只保留日期部分
                        "annotationStatus": annotation_status  # 添加标注状态
                    })
                
                result["data"] = extracted_items
                result["success"] = True
                result["message"] = f"成功获取到 {len(extracted_items)} 条废弃项目记录"
            
        return result
            
    except Exception as e:
        print(f"获取废弃项目列表失败: {str(e)}")
        import traceback
        print(f"错误详情: {traceback.format_exc()}")
        return {
            "success": False,
            "message": str(e),
            "total": 0,
            "data": [],
            "status_code": 0
        }

def get_item_list(task_id, node_id, package_ids, page_num=1, page_size=50, headers=None):
    """
    调用get-item-list接口获取项目列表并返回特定字段
    
    Args:
        task_id (str): 任务ID
        node_id (str): 节点ID
        package_ids (str or list): 批次ID，可以是单个ID或ID列表
        page_num (int): 页码，默认为1
        page_size (int): 每页数量，默认为50
        headers (dict, optional): 自定义请求头，如果为None则使用默认请求头
    
    Returns:
        dict: 包含状态信息和数据的字典
    """
    # 构建请求URL
    url = "https://app.molardata.com/api/v2/item/get-item-list"
    
    # 确保package_ids是列表格式
    if isinstance(package_ids, str):
        package_ids = [package_ids]
    
    # 如果未提供自定义请求头，使用默认请求头
    if headers is None:
        referer_batch_id = package_ids[0] if package_ids else "68d28091dd785cd49b388c61"
        headers = get_default_headers(task_id=task_id, batch_id=referer_batch_id)
    
    data = {
        "taskId": task_id,
        "pageNum": page_num,
        "pageSize": page_size,
        "search": {
            "type": "AND",
            "units": []
        },
        "packageIds": package_ids,
        "nodeId": node_id
    }
    
    try:
        print("\n正在获取项目列表...")
        # 打印请求参数（隐藏敏感信息）
        masked_headers = headers.copy()
        if 'access-token' in masked_headers:
            token = masked_headers['access-token']
            masked_headers['access-token'] = f"{token[:10]}****{token[-4:]}"
        print(f"请求URL: {url}")
        print(f"请求参数: taskId={task_id}, nodeId={node_id}, packageIds={package_ids}")
        print(f"请求头(部分): {dict(list(masked_headers.items())[:3])}")
        
        response = requests.post(url, headers=headers, json=data, timeout=60)
        status_code = response.status_code
        print(f"请求状态码: {status_code}")
        
        # 无论状态码如何，都尝试解析响应内容
        try:
            response_data = response.json()
            print(f"响应内容(部分): {json.dumps(response_data)[:200]}...")
        except json.JSONDecodeError:
            response_data = None
            print(f"响应内容(非JSON): {response.text[:200]}...")
        
        # 如果返回401错误，尝试切换token并重新请求
        if status_code == 401:
            print("\n[错误] 认证失败 (401 Unauthorized)")
            print("尝试切换到备用token...")
            switch_token("alternative_token")
            # 使用新token重新构建请求头
            headers = get_default_headers(task_id=task_id, batch_id=referer_batch_id)
            print("使用新token重新请求...")
            response = requests.post(url, headers=headers, json=data, timeout=60)
            status_code = response.status_code
            print(f"新请求状态码: {status_code}")
            try:
                response_data = response.json()
                print(f"新响应内容(部分): {json.dumps(response_data)[:200]}...")
            except json.JSONDecodeError:
                response_data = None
                print(f"新响应内容(非JSON): {response.text[:200]}...")
        
        # 处理500错误
        elif status_code == 500:
            print("\n[错误] 服务器内部错误 (500)")
            # 尝试使用不同的批次ID或简化参数
            print("尝试使用简化的请求参数...")
            # 使用默认批次ID
            test_package_ids = ["68d28091dd785cd49b388c61"]  # 默认批次ID
            test_data = {
                "taskId": task_id,
                "pageNum": 1,
                "pageSize": 10,  # 减少页面大小
                "packageIds": test_package_ids,
                "nodeId": node_id
            }
            print(f"使用测试参数: packageIds={test_package_ids}, pageSize=10")
            
            # 重新发送请求
            test_response = requests.post(url, headers=headers, json=test_data, timeout=60)
            test_status_code = test_response.status_code
            print(f"测试请求状态码: {test_status_code}")
            
            try:
                response_data = test_response.json()
                print(f"测试响应内容(部分): {json.dumps(response_data)[:200]}...")
            except json.JSONDecodeError:
                response_data = None
                print(f"测试响应内容(非JSON): {test_response.text[:200]}...")
            
            status_code = test_status_code
        
        result = {
            "success": False,
            "message": "",
            "total": 0,
            "data": [],
            "status_code": status_code
        }
        
        if response_data and 'data' in response_data and isinstance(response_data['data'], dict):
            total = response_data['data'].get('total', 0)
            result["total"] = total
            
            if 'data' in response_data['data'] and isinstance(response_data['data']['data'], list):
                items = response_data['data']['data']
                extracted_items = []
                
                # 添加调试信息，查看前5条记录的processStatus字段内容
                with open('process_status_debug.txt', 'w', encoding='utf-8') as debug_file:
                    debug_file.write("调试信息 - processStatus字段分析\n")
                    debug_file.write("="*50 + "\n\n")
                    
                    debug_count = 0
                    for item in items:
                        if debug_count < 5:
                            process_status = item.get('processStatus', None)
                            debug_file.write(f"记录ID: {item.get('_id', 'N/A')}\n")
                            debug_file.write(f"processStatus类型: {type(process_status)}\n")
                            debug_file.write(f"processStatus内容: {process_status}\n")
                            if isinstance(process_status, dict):
                                debug_file.write(f"processStatus键: {list(process_status.keys())}\n")
                                # 检查checkRound字段是否存在及值
                                if 'checkRound' in process_status:
                                    debug_file.write(f"checkRound值: {process_status['checkRound']}\n")
                                else:
                                    debug_file.write("checkRound字段: 不存在\n")
                            debug_file.write("-"*50 + "\n")
                            debug_count += 1
                        
                        # 提取processStatus和checkRound来判断标注状态
                        process_status = item.get('processStatus', None)
                        if process_status is not None and isinstance(process_status, dict):
                            # 结合checkRound和label字段来判断标注状态
                            has_check_round = 'checkRound' in process_status
                            label_value = process_status.get('label', '')
                            
                            # 如果label字段为LABELED且有checkRound，则为已标注
                            # 否则为标注中
                            if label_value == 'LABELED' and has_check_round:
                                annotation_status = '已标注'
                            else:
                                annotation_status = '标注中'
                        else:
                            # 如果没有processStatus对象，默认为标注中
                            annotation_status = '标注中'
                        
                        # 获取operateTime或createdAt，只保留日期部分
                        time_value = item.get('operateTime', item.get('createdAt', 'N/A'))
                        # 如果时间值不为N/A，尝试提取日期部分
                        if time_value != 'N/A':
                            # 确保时间值是字符串
                            time_str = str(time_value)
                            # 处理不同格式的时间字符串
                            if ' ' in time_str:  # 处理包含空格的格式，如"2023-10-15 12:34:56"
                                formatted_date = time_str.split(' ')[0]
                            elif 'T' in time_str:  # 处理ISO格式，如"2023-10-15T12:34:56Z"
                                formatted_date = time_str.split('T')[0]
                            elif len(time_str) >= 10:  # 处理其他可能的格式，只取前10个字符
                                formatted_date = time_str[:10]
                            else:
                                formatted_date = time_str
                        else:
                            formatted_date = 'N/A'
                        
                        extracted_items.append({
                            "_id": item.get('_id', 'N/A'),
                            "domainId": item.get('domainId', 'N/A'),
                            "operateTime": formatted_date,  # 只保留日期部分
                            "annotationStatus": annotation_status  # 添加标注状态
                        })
                print("调试信息已写入 process_status_debug.txt 文件")
                
                result["data"] = extracted_items
                result["success"] = True
                result["message"] = f"成功获取到 {len(extracted_items)} 条记录"
            
        return result
            
    except Exception as e:
        print(f"获取项目列表失败: {str(e)}")
        import traceback
        print(f"错误详情: {traceback.format_exc()}")
        return {
            "success": False,
            "message": str(e),
            "total": 0,
            "data": [],
            "status_code": 0
        }

def get_item_skip_list(task_id, node_id, package_ids, page_num=1, page_size=50, headers=None):
    """
    调用get-item-skip-list接口获取被跳过的项目列表
    
    Args:
        task_id (str): 任务ID
        node_id (str): 节点ID
        package_ids (str or list): 批次ID，可以是单个ID或ID列表
        page_num (int): 页码，默认为1
        page_size (int): 每页数量，默认为50
        headers (dict, optional): 自定义请求头，如果为None则使用默认请求头
    
    Returns:
        dict: 包含状态信息和数据的字典
    """
    # 构建请求URL
    url = "https://app.molardata.com/api/v2/item/get-item-skip-list"
    
    # 确保package_ids是列表格式
    if isinstance(package_ids, str):
        package_ids = [package_ids]
    
    # 如果未提供自定义请求头，使用默认请求头
    if headers is None:
        referer_batch_id = package_ids[0] if package_ids else "68d28091dd785cd49b388c61"
        headers = get_default_headers(task_id=task_id, batch_id=referer_batch_id)
    
    data = {
        "taskId": task_id,
        "pageNum": page_num,
        "pageSize": page_size,
        "search": {
            "type": "AND",
            "units": []
        },
        "packageIds": package_ids,
        "nodeId": node_id
    }
    
    try:
        print("\n正在获取被跳过项目列表...")
        # 打印请求参数（隐藏敏感信息）
        masked_headers = headers.copy()
        if 'access-token' in masked_headers:
            token = masked_headers['access-token']
            masked_headers['access-token'] = f"{token[:10]}****{token[-4:]}"
        print(f"请求URL: {url}")
        print(f"请求参数: taskId={task_id}, nodeId={node_id}, packageIds={package_ids}")
        print(f"请求头(部分): {dict(list(masked_headers.items())[:3])}")
        
        response = requests.post(url, headers=headers, json=data, timeout=60)
        status_code = response.status_code
        print(f"请求状态码: {status_code}")
        
        # 无论状态码如何，都尝试解析响应内容
        try:
            response_data = response.json()
            print(f"响应内容(部分): {json.dumps(response_data)[:200]}...")
        except json.JSONDecodeError:
            response_data = None
            print(f"响应内容(非JSON): {response.text[:200]}...")
        
        # 如果返回401错误，尝试切换token并重新请求
        if status_code == 401:
            print("\n[错误] 认证失败 (401 Unauthorized)")
            print("尝试切换到备用token...")
            switch_token("alternative_token")
            # 使用新token重新构建请求头
            headers = get_default_headers(task_id=task_id, batch_id=referer_batch_id)
            print("使用新token重新请求...")
            response = requests.post(url, headers=headers, json=data, timeout=60)
            status_code = response.status_code
            print(f"新请求状态码: {status_code}")
            try:
                response_data = response.json()
                print(f"新响应内容(部分): {json.dumps(response_data)[:200]}...")
            except json.JSONDecodeError:
                response_data = None
                print(f"新响应内容(非JSON): {response.text[:200]}...")
        
        # 处理500错误
        elif status_code == 500:
            print("\n[错误] 服务器内部错误 (500)")
            print("尝试使用简化的请求参数...")
            # 使用默认批次ID
            test_package_ids = ["68d28091dd785cd49b388c61"]  # 默认批次ID
            test_data = {
                "taskId": task_id,
                "pageNum": 1,
                "pageSize": 10,  # 减少页面大小
                "packageIds": test_package_ids,
                "nodeId": node_id
            }
            print(f"使用测试参数: packageIds={test_package_ids}, pageSize=10")
            
            # 重新发送请求
            test_response = requests.post(url, headers=headers, json=test_data, timeout=60)
            test_status_code = test_response.status_code
            print(f"测试请求状态码: {test_status_code}")
            
            try:
                response_data = test_response.json()
                print(f"测试响应内容(部分): {json.dumps(response_data)[:200]}...")
            except json.JSONDecodeError:
                response_data = None
                print(f"测试响应内容(非JSON): {test_response.text[:200]}...")
            
            status_code = test_status_code
        
        result = {
            "success": False,
            "message": "",
            "total": 0,
            "data": [],
            "status_code": status_code
        }
        
        if response_data and 'data' in response_data and isinstance(response_data['data'], dict):
            total = response_data['data'].get('total', 0)
            result["total"] = total
            
            if 'data' in response_data['data'] and isinstance(response_data['data']['data'], list):
                items = response_data['data']['data']
                extracted_items = []
                
                for item in items:
                    # 跳过的项目直接设置状态为"已跳过"
                    # 获取operateTime或createdAt，只保留日期部分
                    time_value = item.get('operateTime', item.get('createdAt', 'N/A'))
                    # 如果时间值不为N/A，尝试提取日期部分
                    if time_value != 'N/A':
                        # 确保时间值是字符串
                        time_str = str(time_value)
                        # 处理不同格式的时间字符串
                        if ' ' in time_str:  # 处理包含空格的格式，如"2023-10-15 12:34:56"
                            formatted_date = time_str.split(' ')[0]
                        elif 'T' in time_str:  # 处理ISO格式，如"2023-10-15T12:34:56Z"
                            formatted_date = time_str.split('T')[0]
                        elif len(time_str) >= 10:  # 处理其他可能的格式，只取前10个字符
                            formatted_date = time_str[:10]
                        else:
                            formatted_date = time_str
                    else:
                        formatted_date = 'N/A'
                    
                    extracted_items.append({
                        "_id": item.get('_id', 'N/A'),
                        "domainId": item.get('domainId', 'N/A'),
                        "operateTime": formatted_date,  # 只保留日期部分
                        "annotationStatus": "已跳过"  # 跳过的项目直接设置为"已跳过"
                    })
                
                result["data"] = extracted_items
                result["success"] = True
                result["message"] = f"成功获取到 {len(extracted_items)} 条被跳过的项目记录"
            
        return result
            
    except Exception as e:
        print(f"获取被跳过项目列表失败: {str(e)}")
        import traceback
        print(f"错误详情: {traceback.format_exc()}")
        return {
            "success": False,
            "message": str(e),
            "total": 0,
            "data": [],
            "status_code": 0
        }

def get_item_abandon_list(task_id, node_id, package_ids, page_num=1, page_size=50, headers=None):
    """
    调用get-item-abandon-list接口获取被放弃的项目列表
    
    Args:
        task_id (str): 任务ID
        node_id (str): 节点ID
        package_ids (str or list): 批次ID，可以是单个ID或ID列表
        page_num (int): 页码，默认为1
        page_size (int): 每页数量，默认为50
        headers (dict, optional): 自定义请求头，如果为None则使用默认请求头
    
    Returns:
        dict: 包含状态信息和数据的字典
    """
    # 构建请求URL
    url = "https://app.molardata.com/api/v2/item/get-item-abandon-list"
    
    # 确保package_ids是列表格式
    if isinstance(package_ids, str):
        package_ids = [package_ids]
    
    # 如果未提供自定义请求头，使用默认请求头
    if headers is None:
        referer_batch_id = package_ids[0] if package_ids else "68d28091dd785cd49b388c61"
        headers = get_default_headers(task_id=task_id, batch_id=referer_batch_id)
    
    data = {
        "taskId": task_id,
        "pageNum": page_num,
        "pageSize": page_size,
        "search": {
            "type": "AND",
            "units": []
        },
        "packageIds": package_ids,
        "nodeId": node_id
    }
    
    try:
        print("\n正在获取被放弃项目列表...")
        # 打印请求参数（隐藏敏感信息）
        masked_headers = headers.copy()
        if 'access-token' in masked_headers:
            token = masked_headers['access-token']
            masked_headers['access-token'] = f"{token[:10]}****{token[-4:]}"
        print(f"请求URL: {url}")
        print(f"请求参数: taskId={task_id}, nodeId={node_id}, packageIds={package_ids}")
        print(f"请求头(部分): {dict(list(masked_headers.items())[:3])}")
        
        response = requests.post(url, headers=headers, json=data, timeout=60)
        status_code = response.status_code
        print(f"请求状态码: {status_code}")
        
        # 无论状态码如何，都尝试解析响应内容
        try:
            response_data = response.json()
            print(f"响应内容(部分): {json.dumps(response_data)[:200]}...")
        except json.JSONDecodeError:
            response_data = None
            print(f"响应内容(非JSON): {response.text[:200]}...")
        
        # 如果返回401错误，尝试切换token并重新请求
        if status_code == 401:
            print("\n[错误] 认证失败 (401 Unauthorized)")
            print("尝试切换到备用token...")
            switch_token("alternative_token")
            # 使用新token重新构建请求头
            headers = get_default_headers(task_id=task_id, batch_id=referer_batch_id)
            print("使用新token重新请求...")
            response = requests.post(url, headers=headers, json=data, timeout=60)
            status_code = response.status_code
            print(f"新请求状态码: {status_code}")
            try:
                response_data = response.json()
                print(f"新响应内容(部分): {json.dumps(response_data)[:200]}...")
            except json.JSONDecodeError:
                response_data = None
                print(f"新响应内容(非JSON): {response.text[:200]}...")
        
        # 处理500错误
        elif status_code == 500:
            print("\n[错误] 服务器内部错误 (500)")
            print("尝试使用简化的请求参数...")
            # 使用默认批次ID
            test_package_ids = ["68d28091dd785cd49b388c61"]  # 默认批次ID
            test_data = {
                "taskId": task_id,
                "pageNum": 1,
                "pageSize": 10,  # 减少页面大小
                "packageIds": test_package_ids,
                "nodeId": node_id
            }
            print(f"使用测试参数: packageIds={test_package_ids}, pageSize=10")
            
            # 重新发送请求
            test_response = requests.post(url, headers=headers, json=test_data, timeout=60)
            test_status_code = test_response.status_code
            print(f"测试请求状态码: {test_status_code}")
            
            try:
                response_data = test_response.json()
                print(f"测试响应内容(部分): {json.dumps(response_data)[:200]}...")
            except json.JSONDecodeError:
                response_data = None
                print(f"测试响应内容(非JSON): {test_response.text[:200]}...")
            
            status_code = test_status_code
        
        result = {
            "success": False,
            "message": "",
            "total": 0,
            "data": [],
            "status_code": status_code
        }
        
        if response_data and 'data' in response_data and isinstance(response_data['data'], dict):
            total = response_data['data'].get('total', 0)
            result["total"] = total
            
            if 'data' in response_data['data'] and isinstance(response_data['data']['data'], list):
                items = response_data['data']['data']
                extracted_items = []
                
                for item in items:
                    # 被放弃的项目直接设置状态为"已放弃"
                    extracted_items.append({
                        "_id": item.get('_id', 'N/A'),
                        "domainId": item.get('domainId', 'N/A'),
                        "operateTime": item.get('operateTime', item.get('createdAt', 'N/A')),  # 使用operateTime，不存在时使用createdAt作为备选
                        "annotationStatus": "已放弃"  # 被放弃的项目直接设置为"已放弃"
                    })
                
                result["data"] = extracted_items
                result["success"] = True
                result["message"] = f"成功获取到 {len(extracted_items)} 条被放弃的项目记录"
            
        return result
            
    except Exception as e:
        print(f"获取被放弃项目列表失败: {str(e)}")
        import traceback
        print(f"错误详情: {traceback.format_exc()}")
        return {
            "success": False,
            "message": str(e),
            "total": 0,
            "data": [],
            "status_code": 0
        }

def get_find_labels(task_id, item_id, headers=None):
    """
    调用find-labels接口获取项目的标签信息，特别是统计区域删除标签数量
    
    Args:
        task_id (str): 任务ID
        item_id (str): 项目ID
        headers (dict, optional): 自定义请求头
    
    Returns:
        dict: {item_id: area_delete_count} 区域删除标签数量
    """
    url = "https://app.molardata.com/api/v2/label/find-labels"
    
    if headers is None:
        # 使用默认请求头
        headers = get_default_headers(task_id=task_id, batch_id=item_id)
    
    # 打印请求头信息（隐藏敏感信息）
    masked_headers = headers.copy()
    if 'access-token' in masked_headers:
        token = masked_headers['access-token']
        masked_headers['access-token'] = f"{token[:10]}****{token[-4:]}"
    print(f"\nget_find_labels - 请求头(部分): {dict(list(masked_headers.items())[:3])}")
    print(f"请求参数: taskId={task_id}, itemId={item_id}")
    
    payload = {
        "itemId": item_id,
        "taskId": task_id
    }
    
    try:
        print(f"正在获取项目 {item_id} 的标签信息...")
        response = requests.post(url, headers=headers, json=payload, timeout=30)
        print(f"响应状态码: {response.status_code}")
        
        # 如果返回401错误，尝试切换token并重新请求
        if response.status_code == 401:
            print("\n[错误] 认证失败 (401 Unauthorized)")
            print("尝试切换到备用token...")
            switch_token("alternative_token")
            # 使用新token重新构建请求头
            headers = get_default_headers(task_id=task_id, batch_id=item_id)
            print("使用新token重新请求...")
            response = requests.post(url, headers=headers, json=payload, timeout=30)
            print(f"新请求状态码: {response.status_code}")
        
        # 尝试解析响应内容
        try:
            response_data = response.json()
            print(f"响应内容(部分): {json.dumps(response_data)[:200]}...")
        except json.JSONDecodeError:
            print(f"响应内容不是有效的JSON: {response.text[:200]}...")
            return {item_id: 0}
        
        # 统计区域删除标签数量
        area_delete_count = 0
        
        # 根据实际响应结构处理
        if isinstance(response_data, dict):
            # 检查response_data.data是否为列表
            if isinstance(response_data.get("data"), list):
                # 遍历标签数组
                for item in response_data["data"]:
                    if isinstance(item, dict) and "data" in item and isinstance(item["data"], dict):
                        # 检查item.data.label是否为"区域删除"
                        if item["data"].get("label") == "区域删除":
                            area_delete_count += 1
                            print(f"找到区域删除标签: {item.get('_id', '未知ID')}")
            else:
                print(f"响应data字段不是列表: {type(response_data.get('data'))}")
        
        print(f"项目 {item_id} 区域删除标签数量: {area_delete_count}")
        return {item_id: area_delete_count}
        
    except Exception as e:
        print(f"获取标签信息失败: {str(e)}")
        import traceback
        print(f"错误详情: {traceback.format_exc()}")
        return {item_id: 0}

def get_find_labels_batch(task_id, item_ids, headers=None):
    """
    批量调用find-labels接口获取多个项目的区域删除标签数量
    
    Args:
        task_id (str): 任务ID
        item_ids (list): 项目ID列表
        headers (dict, optional): 自定义请求头
    
    Returns:
        dict: 所有项目的区域删除标签数量，格式为{item_id: area_delete_count}
    """
    all_labels = {}
    
    print(f"\n===== 获取{len(item_ids)}个项目的标签信息 =====")
    
    # 逐个调用find-labels接口
    for i, item_id in enumerate(item_ids, 1):
        print(f"\n[{i}/{len(item_ids)}]")
        label_info = get_find_labels(task_id, item_id, headers)
        if label_info:
            all_labels.update(label_info)
    
    print(f"\n成功获取{len(all_labels)}个项目的标签信息")
    return all_labels

def get_item_detail(task_id, node_id, item_ids, headers=None):
    """
    调用get-item-detail接口获取项目详细信息，提取labeler相关信息、checkStatus和nodeId
    
    Args:
        task_id (str): 任务ID
        node_id (str): 节点ID
        item_ids (list): 项目ID列表
        headers (dict, optional): 自定义请求头
    
    Returns:
        tuple: (labeler_info, check_status_info, node_id_info)，包含item_id对应的标注人、审核状态和节点信息
    """
    url = "https://app.molardata.com/api/v2/item/get-item-detail"
    
    if headers is None:
        # 使用默认批次ID或从item_ids中获取第一个作为referer中的batchId
        referer_batch_id = item_ids[0] if item_ids else "68d28091dd785cd49b388c61"
        headers = get_default_headers(task_id=task_id, batch_id=referer_batch_id)
    
    # 打印请求头信息（隐藏敏感信息）
    masked_headers = headers.copy()
    if 'access-token' in masked_headers:
        token = masked_headers['access-token']
        masked_headers['access-token'] = f"{token[:10]}****{token[-4:]}"
    print(f"\nget_item_detail - 请求头(部分): {dict(list(masked_headers.items())[:3])}")
    print(f"请求参数: taskId={task_id}, nodeId={node_id}, item_ids数量={len(item_ids)}")
    
    payload = {
        "taskId": task_id,
        "ai": False,
        "nodeId": node_id,
        "itemIds": item_ids
    }
    
    try:
        print(f"\n正在获取 {len(item_ids)} 个项目的详细信息...")
        response = requests.post(url, headers=headers, json=payload, timeout=30)
        print(f"响应状态码: {response.status_code}")
        
        # 如果返回401错误，尝试切换token并重新请求
        if response.status_code == 401:
            print("\n[错误] 认证失败 (401 Unauthorized)")
            print("尝试切换到备用token...")
            switch_token("alternative_token")
            # 使用新token重新构建请求头
            headers = get_default_headers(task_id=task_id, batch_id=referer_batch_id)
            print("使用新token重新请求...")
            response = requests.post(url, headers=headers, json=payload, timeout=30)
            print(f"新请求状态码: {response.status_code}")
        
        # 尝试解析响应内容
        try:
            response_data = response.json()
            print(f"响应内容(部分): {json.dumps(response_data)[:200]}...")
        except json.JSONDecodeError:
            print(f"响应内容不是有效的JSON: {response.text[:200]}...")
            return {}, {}
        
        labeler_info = {}
        check_status_info = {}
        node_id_info = {}
        
        if 'data' in response_data and isinstance(response_data['data'], dict):
            print("正在提取labeler信息和checkStatus...")
            
            for item_id, item_detail in response_data['data'].items():
                username = "-"
                check_status = "-"
                
                # 尝试从labeler字段获取username
                if isinstance(item_detail, dict):
                    # 获取标注人信息
                    if 'labeler' in item_detail and isinstance(item_detail['labeler'], dict):
                        username = item_detail['labeler'].get('username', '-')
                    
                    # 获取checkStatus信息
                    if 'checkStatus' in item_detail:
                        check_status = item_detail.get('checkStatus', '-')
                    # 或者检查processStatus中的check相关字段
                    elif 'processStatus' in item_detail and isinstance(item_detail['processStatus'], dict):
                        check_status = item_detail['processStatus'].get('checkStatus', '-')
                    
                    # 获取nodeId信息
                    node_id_value = '-'  
                    if 'nodeId' in item_detail:
                        node_id_value = item_detail.get('nodeId', '-')
                    # 或者检查processStatus中的nodeId
                    elif 'processStatus' in item_detail and isinstance(item_detail['processStatus'], dict):
                        node_id_value = item_detail['processStatus'].get('nodeId', '-')
                
                labeler_info[item_id] = username
                check_status_info[item_id] = check_status
                node_id_info[item_id] = node_id_value
            
            print(f"成功提取 {len(labeler_info)} 条labeler信息、{len(check_status_info)} 条checkStatus信息和 {len(node_id_info)} 条nodeId信息")
        else:
            print("响应数据格式不符合预期")
            if response_data:
                print(f"响应结构: {list(response_data.keys())}")
                
        return labeler_info, check_status_info, node_id_info
        
    except Exception as e:
        print(f"获取项目详情失败: {str(e)}")
        import traceback
        print(f"错误详情: {traceback.format_exc()}")
        return {}, {}, {}

def extract_id_and_frames(task_id, node_id, item_ids, ai=False):
    """
    调用find-items-file接口，提取item_id和frames字段
    
    Args:
        task_id (str): 任务ID
        node_id (str): 节点ID
        item_ids (list): 项目ID列表
        ai (bool): 是否使用AI
    
    Returns:
        list: 包含id和frames的列表
    """
    url = "https://app.molardata.com/api/v2/item/find-items-file"
    
    # 使用默认批次ID或从item_ids中获取第一个作为referer中的batchId
    referer_batch_id = item_ids[0] if item_ids else "68d28091dd785cd49b388c61"
    headers = get_default_headers(task_id=task_id, batch_id=referer_batch_id)
    
    # 打印请求头信息（隐藏敏感信息）
    masked_headers = headers.copy()
    if 'access-token' in masked_headers:
        token = masked_headers['access-token']
        masked_headers['access-token'] = f"{token[:10]}****{token[-4:]}"
    print(f"\nextract_id_and_frames - 请求头(部分): {dict(list(masked_headers.items())[:3])}")
    print(f"请求参数: taskId={task_id}, nodeId={node_id}, item_ids数量={len(item_ids)}, ai={ai}")
    
    payload = {
        "taskId": task_id,
        "ai": ai,
        "nodeId": node_id,
        "itemIds": item_ids
    }
    
    try:
        print(f"\n正在获取 {len(item_ids)} 个项目的文件信息...")
        response = requests.post(url, headers=headers, json=payload, timeout=30)
        print(f"响应状态码: {response.status_code}")
        
        # 如果返回401错误，尝试切换token并重新请求
        if response.status_code == 401:
            print("\n[错误] 认证失败 (401 Unauthorized)")
            print("尝试切换到备用token...")
            switch_token("alternative_token")
            # 使用新token重新构建请求头
            headers = get_default_headers(task_id=task_id, batch_id=referer_batch_id)
            print("使用新token重新请求...")
            response = requests.post(url, headers=headers, json=payload, timeout=30)
            print(f"新请求状态码: {response.status_code}")
        
        # 尝试解析响应内容
        try:
            response_data = response.json()
            print(f"响应内容(部分): {json.dumps(response_data)[:200]}...")
        except json.JSONDecodeError:
            print(f"响应内容不是有效的JSON: {response.text[:200]}...")
            return []
        
        simplified_data = []
        
        if "data" in response_data and isinstance(response_data["data"], dict):
            print("正在提取ID和frames信息...")
            
            for item_id, item_info in response_data["data"].items():
                frames = item_info.get("frames", 0)
                simplified_data.append({
                    "id": item_id,
                    "frames": frames
                })
            
            print(f"成功提取 {len(simplified_data)} 条记录")
        else:
            print("响应数据格式不符合预期")
            if response_data:
                print(f"响应结构: {list(response_data.keys())}")
            
        return simplified_data
        
    except Exception as e:
        print(f"提取文件信息失败: {str(e)}")
        import traceback
        print(f"错误详情: {traceback.format_exc()}")
        return []

def convert_to_beijing_time(utc_time_str):
    """
    将UTC时间字符串转换为北京时间
    
    Args:
        utc_time_str (str): UTC时间字符串，格式如 "2025-09-23T11:13:37.488Z"
    
    Returns:
        str: 北京时间字符串，格式为 "2025-09-23 19:13:37"
    """
    if not utc_time_str or not isinstance(utc_time_str, str):
        return utc_time_str
    
    try:
        # 移除可能的毫秒部分
        if '.' in utc_time_str:
            utc_time_str = utc_time_str.split('.')[0] + 'Z'
        
        # 解析UTC时间
        utc_time = datetime.strptime(utc_time_str, "%Y-%m-%dT%H:%M:%SZ")
        
        # 转换为北京时间（UTC+8）
        beijing_time = utc_time + timedelta(hours=8)
        
        # 格式化为更友好的字符串
        return beijing_time.strftime("%Y-%m-%d %H:%M:%S")
    except Exception:
        # 如果解析失败，返回原始字符串
        return utc_time_str

def correlate_and_display(item_list_data, frames_data, labeler_info=None, check_status_info=None, node_id_info=None, labels_info=None, export_to_excel=True):
    """
    关联并显示项目列表、frames信息、labeler信息和checkStatus
    
    Args:
        item_list_data (list): 从get_item_list、get_item_abandon_list获取的数据列表（已在main中处理跳过状态）
        frames_data (list): 从extract_id_and_frames获取的数据列表
        labeler_info (dict, optional): 从get_item_detail获取的labeler信息
        check_status_info (dict, optional): 从get_item_detail获取的checkStatus信息
        node_id_info (dict, optional): 从get_item_detail获取的nodeId信息
        labels_info (dict, optional): 从get_find_labels_batch获取的标签信息
        export_to_excel (bool): 是否导出到Excel表格，默认为True
    """
    if not item_list_data:
        print("没有项目数据可显示")
        return
    
    # 创建frames数据的字典，方便快速查找
    frames_dict = {item["id"]: item["frames"] for item in frames_data} if frames_data else {}
    
    print("\n===== 项目信息、Frames与标注人关联结果 =====")
    
    # 根据是否有labeler信息决定表头
    if labeler_info:
        print(f"{'序号':<6}{'ID':<32}{'domainId':<10}{'operateTime':<20}{'Frames':<8}{'标注状态':<8}{'标注人':<10}")
        print("-" * 104)
    else:
        print(f"{'序号':<6}{'ID':<32}{'domainId':<10}{'operateTime':<20}{'Frames':<8}{'标注状态':<8}")
        print("-" * 94)
    
    # 统计信息
    matched_count = 0
    unmatched_count = 0
    labeled_count = 0
    annotated_count = 0  # 已标注数量
    annotating_count = 0  # 标注中数量
    abandoned_count = 0  # 已放弃数量
    skipped_count = 0  # 已跳过数量
    
    # 准备Excel导出数据
    excel_data = []
    
    # 遍历项目列表数据，关联frames和labeler信息
    for idx, item in enumerate(item_list_data, 1):
        item_id = item["_id"]
        frames = frames_dict.get(item_id, "未找到")
        username = labeler_info.get(item_id, "-") if labeler_info else "-"
        check_status = check_status_info.get(item_id, "-") if check_status_info else "-"
        node_id_value = node_id_info.get(item_id, "-") if node_id_info else "-"
        domain_id = item.get("domainId", "")
        
        # 直接使用项目中的annotationStatus字段（已在main函数中处理了跳过状态）
        annotation_status = item.get("annotationStatus", "未知")
        
        # 去除可能的换行符
        if isinstance(username, str):
            username = username.replace('\n', '')
        
        # 转换为北京时间
        beijing_time = convert_to_beijing_time(item['operateTime'])
        
        # 统计区域删除数量
        area_delete_count = 0
        if labels_info and item_id in labels_info:
            # 现在labels_info[item_id]直接是区域删除标签的数量（整数）
            area_delete_count = int(labels_info[item_id])
        
        # 构建导出数据
        row_data = {
            '序号': idx,
            'ID': item_id,
            'domainId': domain_id,
            'operateTime': beijing_time,  # 使用北京时间
            'Frames': frames,
            '标注状态': annotation_status,
            'checkStatus': check_status,
            'nodeId': node_id_value,
            '区域删除': area_delete_count  # 添加区域删除统计
        }
        if labeler_info:
            row_data['标注人'] = username
        excel_data.append(row_data)
        
        if labeler_info:
            print(f"{idx:<6}{item_id:<32}{str(domain_id):<10}{beijing_time:<20}{str(frames):<8}{annotation_status:<8}{username:<10}")
        else:
            print(f"{idx:<6}{item_id:<32}{str(domain_id):<10}{beijing_time:<20}{str(frames):<8}{annotation_status:<8}")
        
        if frames != "未找到":
            matched_count += 1
        else:
            unmatched_count += 1
        
        if username != "-":
            labeled_count += 1
        
        # 根据标注状态统计
        if annotation_status == "已标注":
            annotated_count += 1
        elif annotation_status == "标注中":
            annotating_count += 1
        elif annotation_status == "已放弃":
            abandoned_count += 1
        elif annotation_status == "已跳过":
            skipped_count += 1
    
    # 打印统计信息
    if labeler_info:
        print("-" * 104)
        print(f"总计: {len(item_list_data)} 条项目记录")
        print(f"成功关联Frames: {matched_count} 条")
        print(f"未找到Frames匹配: {unmatched_count} 条")
        print(f"有标注人信息: {labeled_count} 条")
        print(f"无标注人信息: {len(item_list_data) - labeled_count} 条")
        print(f"已标注: {annotated_count} 条")
        print(f"标注中: {annotating_count} 条")
        print(f"已放弃: {abandoned_count} 条")
        print(f"已跳过: {skipped_count} 条")
    else:
        print("-" * 94)
        print(f"总计: {len(item_list_data)} 条项目记录")
        print(f"成功关联Frames: {matched_count} 条")
        print(f"未找到Frames匹配: {unmatched_count} 条")
        print(f"已标注: {annotated_count} 条")
        print(f"标注中: {annotating_count} 条")
        print(f"已放弃: {abandoned_count} 条")
        print(f"已跳过: {skipped_count} 条")
    
    # 导出到Excel
    if export_to_excel and excel_data:
        try:
            # 创建checkStatus映射字典
            check_status_mapping = {
                'APPROVED': '审核通过',
                'RE_APPROVED': '复审通过', 
                'REJECTED': '审核不通过',
                'SKIP': '已跳过',
                'UNCHECKED': '未审核',
                'CHECKING': '审核中',
                'UNRECHECKED': '未复审',
            }
            
            # 创建nodeId映射字典
            node_id_mapping = {
                '68ee06dd8b09f9d346b6d37b': '搁置',
                '68d255e332a0f5d164c7082e': '审核',
                '68d255e332a0f5d164c7082d': '标注内审',
                '68d9ee42fd32a29543c7e1a4': '标注内审2',
                '68d255e332a0f5d164c7082f': '验收',
                '68d255e332a0f5d164c7082c': '标注',
                '68da1d528bb1370c422d13ec': '标注内审2',
                '68d4aa85885469ceef9626e4': '标注',
                '68d4aa85885469ceef9626e5': '标注内审',
                '68e38ffb138a749868212d4c': '处理ed',
            }
            
            # 创建新的数据结构，只包含需要的列
            new_excel_data = []
            for item in excel_data:
                # 获取并转换checkStatus
                check_status_value = item.get('checkStatus', '-')
                # 如果在映射字典中存在，则转换为中文，否则保持原值
                converted_check_status = check_status_mapping.get(check_status_value, check_status_value)
                
                # 获取并转换nodeId
                node_id_value = item.get('nodeId', '-')
                # 如果在映射字典中存在，则转换为中文，否则保持原值
                converted_node_id = node_id_mapping.get(node_id_value, node_id_value)
                
                # 获取并格式化操作日期
                operate_time = item.get('operateTime', '-')
                if operate_time != '-':
                    # 确保是字符串
                    time_str = str(operate_time)
                    # 处理不同格式的时间字符串
                    if ' ' in time_str:  # 处理包含空格的格式，如"2023-10-15 12:34:56"
                        formatted_date = time_str.split(' ')[0]
                    elif 'T' in time_str:  # 处理ISO格式，如"2023-10-15T12:34:56Z"
                        formatted_date = time_str.split('T')[0]
                    elif len(time_str) >= 10:  # 处理其他可能的格式，只取前10个字符
                        formatted_date = time_str[:10]
                    else:
                        formatted_date = time_str
                else:
                    formatted_date = '-'  
                
                new_item = {
                    '标注人': item.get('标注人', '-'),
                    '空白列': '',
                    '条目号（domainId）': item.get('domainId', ''),
                    '操作日期': formatted_date,  # 确保只显示日期部分
                    '帧数(Frames)': item.get('Frames', ''),
                    '标注状态': item.get('标注状态', ''),
                    '当前审核状态': converted_check_status,
                    '节点类型': converted_node_id,
                    '区域删除': item.get('区域删除', 0)  # 添加区域删除列
                }
                new_excel_data.append(new_item)
            
            # 创建DataFrame
            df = pd.DataFrame(new_excel_data)
            
            # 生成文件名（使用当前时间）
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            filename = f"项目关联结果_{timestamp}.xlsx"
            
            # 保存到Excel
            with pd.ExcelWriter(filename, engine='openpyxl') as writer:
                df.to_excel(writer, index=False, sheet_name='项目数据')
                
                # 获取工作表
                worksheet = writer.sheets['项目数据']
                
                # 设置列宽
                worksheet.column_dimensions['A'].width = 12  # 标注人
                worksheet.column_dimensions['B'].width = 5   # 空白列
                worksheet.column_dimensions['C'].width = 15  # 条目号（domainId）
                worksheet.column_dimensions['D'].width = 12  # 操作日期
                worksheet.column_dimensions['E'].width = 12  # 帧数(Frames)
                worksheet.column_dimensions['F'].width = 12  # 标注状态
                worksheet.column_dimensions['G'].width = 12  # 当前审核状态
                worksheet.column_dimensions['H'].width = 12  # 节点类型
                worksheet.column_dimensions['I'].width = 12  # 区域删除
            
            print(f"\n已成功导出数据到Excel文件: {filename}")
        except Exception as e:
            print(f"导出Excel时出错: {str(e)}")
            # 添加调试信息
            if len(excel_data) > 0:
                print(f"前5行数据示例: {excel_data[:5]}")

def main():
    """
    主函数，整合API调用并关联数据
    """
    print("===== API整合工具 - 项目信息、Frames与标注人关联 =====\n")
    
    # 打印当前配置信息
    print_config_info()
    
    # 配置参数 - 从用户输入获取
    task_id = input("请输入task_id的值 [默认: 68d255e332a0f5d164c7081a]: ") or "68d255e332a0f5d164c7081a"
    node_id = input("请输入node_id的值 [默认: 68d255e332a0f5d164c7082c]: ") or "68d255e332a0f5d164c7082c"
    
    # 获取package_ids
    package_id_input = input("请输入package_id的值 [默认: 68d2831907c5d13e5bc8b64b]: ") or "68d2831907c5d13e5bc8b64b"
    package_ids = [package_id_input]  # 默认作为单个元素的列表
    
    page_num = 1
    
    # 获取page_size
    while True:
        try:
            page_size_input = input("请输入page_size的值 [默认: 1000]: ") or "1000"
            page_size = int(page_size_input)
            break
        except ValueError:
            print("请输入有效的数字！")
    
    print(f"\n配置参数:")
    print(f"  task_id: {task_id}")
    print(f"  node_id: {node_id}")
    print(f"  package_ids: {package_ids}")
    print(f"  page_num: {page_num}")
    print(f"  page_size: {page_size}")
    
    # 步骤1: 获取项目列表数据
    print("\n===== 步骤1: 获取项目列表 =====")
    
    # 获取普通项目列表
    print("获取普通项目列表...")
    normal_item_result = get_item_list(task_id, node_id, package_ids, page_num, page_size)
    
    if not normal_item_result["success"]:
        print(f"获取普通项目列表失败: {normal_item_result['message']}")
        
        # 尝试使用todo_list_extractor作为备选方案
        try:
            print("\n尝试使用get-item-todo-list接口作为备选方案...")
            import todo_list_extractor
            todo_result = todo_list_extractor.get_item_todo_list(task_id, node_id, package_ids)
            
            if todo_result["success"]:
                print(f"成功从todo-list获取到数据，共 {len(todo_result['data'])} 条记录")
                normal_item_list = []
                for item in todo_result['data']:
                    # 获取operateTime或createdAt，只保留日期部分
                    time_value = item.get('operateTime', item.get('createdAt', 'N/A'))
                    # 如果时间值不为N/A，尝试提取日期部分
                    if time_value != 'N/A':
                        # 确保时间值是字符串
                        time_str = str(time_value)
                        # 处理不同格式的时间字符串
                        if ' ' in time_str:  # 处理包含空格的格式，如"2023-10-15 12:34:56"
                            formatted_date = time_str.split(' ')[0]
                        elif 'T' in time_str:  # 处理ISO格式，如"2023-10-15T12:34:56Z"
                            formatted_date = time_str.split('T')[0]
                        elif len(time_str) >= 10:  # 处理其他可能的格式，只取前10个字符
                            formatted_date = time_str[:10]
                        else:
                            formatted_date = time_str
                    else:
                        formatted_date = 'N/A'
                    
                    normal_item_list.append({
                        "_id": item.get('_id', 'N/A'),
                        "domainId": item.get('domainId', 'N/A'),
                        "operateTime": formatted_date,  # 只保留日期部分
                        "annotationStatus": "未知"  # 添加标注状态字段
                    })
                print(f"已转换 {len(normal_item_list)} 条记录用于后续处理")
            else:
                print(f"todo-list接口也调用失败: {todo_result['message']}")
                print("\n程序执行失败。建议检查以下几点:")
                print("1. 确认access-token是否有效")
                print("2. 确认task_id和node_id是否正确")
                print("3. 确认网络连接是否正常")
                return
        except Exception as e:
            print(f"尝试使用备选方案失败: {str(e)}")
            return
    else:
        normal_item_list = normal_item_result["data"]
        print(f"从普通项目列表中提取到 {len(normal_item_list)} 条记录")
    
    # 获取废弃项目列表
    print("\n获取废弃项目列表...")
    abandon_item_result = get_item_abandon_list(task_id, node_id, package_ids, page_num, page_size)
    abandon_item_list = []
    
    if abandon_item_result["success"]:
        abandon_item_list = abandon_item_result["data"]
        # 为废弃项目设置标注状态为"已放弃"
        for item in abandon_item_list:
            item["annotationStatus"] = "已放弃"
        print(f"从废弃项目列表中提取到 {len(abandon_item_list)} 条记录")
    else:
        print(f"获取废弃项目列表失败: {abandon_item_result['message']}")
        print("将继续使用普通项目数据...")
    
    # 合并普通项目和废弃项目
    item_list_data = normal_item_list + abandon_item_list
    
    # 创建项目ID到索引的映射，方便快速查找
    item_id_map = {item["_id"]: idx for idx, item in enumerate(item_list_data)}
    
    # 获取跳过项目列表
    print("\n获取跳过项目列表...")
    skip_item_result = get_item_skip_list(task_id, node_id, package_ids, page_num, page_size)
    
    # 遍历被跳过的项目，在现有项目中查找并修改状态
    skipped_count = 0
    if skip_item_result["success"]:
        skip_items = skip_item_result["data"]
        print(f"获取到 {len(skip_items)} 条被跳过的项目")
        
        for skip_item in skip_items:
            skip_item_id = skip_item.get("_id")
            if skip_item_id in item_id_map:
                # 找到匹配的项目，修改其标注状态为"已跳过"
                item_list_data[item_id_map[skip_item_id]]["annotationStatus"] = "已跳过"
                skipped_count += 1
        print(f"成功将 {skipped_count} 条项目状态修改为'已跳过'")
    else:
        print(f"获取跳过项目列表失败: {skip_item_result['message']}")
        print("将继续使用已有数据...")
    
    # 根据domainId对数据进行排序
    item_list_data.sort(key=lambda x: str(x.get('domainId', '')))
    print(f"已按domainId排序完成")
    
    print(f"\n总计: {len(item_list_data)} 条项目记录 (普通项目: {len(normal_item_list)}, 废弃项目: {len(abandon_item_list)}, 已标记为跳过: {skipped_count})")
    
    if not item_list_data:
        print("没有获取到任何项目数据，程序无法继续")
        return
    
    # 步骤2: 提取所有_id作为参数
    item_ids = [item["_id"] for item in item_list_data]
    if not item_ids:
        print("没有找到有效的item_ids，无法继续")
        return
    print(f"提取到 {len(item_ids)} 个项目ID")
    
    # 步骤3: 调用extract_id_and_frames获取frames信息
    print("\n===== 步骤2: 获取文件信息 =====")
    frames_data = extract_id_and_frames(task_id, node_id, item_ids)
    
    # 步骤4: 调用get_item_detail获取labeler信息、checkStatus和nodeId信息
    print("\n===== 步骤3: 获取标注人信息、checkStatus和节点信息 =====")
    labeler_info, check_status_info, node_id_info = get_item_detail(task_id, node_id, item_ids)
    
    # 步骤5: 获取标签信息，统计区域删除
    print("\n===== 步骤4: 获取标签信息，统计区域删除 =====")
    labels_info = get_find_labels_batch(task_id, item_ids)
    
    # 步骤6: 关联并显示结果
    print("\n===== 步骤5: 关联并显示结果 =====")
    correlate_and_display(item_list_data, frames_data, labeler_info, check_status_info, node_id_info, labels_info, export_to_excel=True)
    
    print("\n===== 程序执行完成 =====")

if __name__ == "__main__":
    main()